package org.bjf.modules.wechatpay.util;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

/**
 * @author bjf
 */
@Slf4j
public class PayUtil {

    private static final String SIGN_KEY = "goodboy";
    // = Application.sContext.getBean(Environment.class).getProperty("secretKey");

    public static String sign(Map<String, String> param) {
        return sign(param, SIGN_KEY);
    }

    public static String sign(Object obj, String signKey) {
        Map<String, String> fieldMap = getFieldMap(obj, Boolean.TRUE);
        return sign(fieldMap, signKey);
    }

    public static String sign(Map<String, String> param, String signKey) {

        log.info("签名前数据:{}", JSON.toJSONString(param));

        //===1.按key字典排序及移除不参与签名的字段
        TreeMap<String, String> sortedMap = new TreeMap<>(param);
        sortedMap.remove("sign");

        //===2.组装签名字符串
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
            String value = entry.getValue();
            if (StringUtils.isNotBlank(value)) {
                //空串不参与签名
                sb.append(entry.getKey()).append("=").append(value).append("&");
            }
        }
        sb.append("key=").append(signKey);

        //===3.MD5签名
        log.info("签名字符串:{}", sb.toString());
        String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
        log.info("MD5签名:{}", sign);
        return sign;
    }


    public static String objectToXml(Object obj) {
        //===1、生成document根节点
        Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement("xml");

        //===2、取对象key-value
        Map<String, String> fieldMap = getFieldMap(obj, Boolean.FALSE);
        for (Entry<String, String> entry : fieldMap.entrySet()) {
            // 生成document文档
            root.addElement(entry.getKey()).addText(String.valueOf(entry.getValue()));
        }

        return doc.asXML();
    }

    public static <T> T xmlToObject(String xmlStr, Class<T> clz) {

        try {
            Document doc = DocumentHelper.parseText(xmlStr);
            Element xml = doc.getRootElement();
            T obj = clz.newInstance();
            Iterator<Element> ite = xml.elementIterator();
            while (ite.hasNext()) {
                Element ele = ite.next();
                String name = ele.getName();
                String value = ele.getText();
                BeanUtils.setProperty(obj, name, value);
            }
            return obj;
        } catch (Exception e) {
            log.error("xml to object 转换出错：" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 根据对象取Map,空值跳过
     */
    private static Map<String, String> getFieldMap(Object obj, boolean ignoreNull) {
        Class clz = obj.getClass();
        //====1.取当前类字段
        Map<String, String> fieldMap = getFieldMap(obj, clz.getDeclaredFields(), ignoreNull);

        //====2.取父类字段
        Map<String, String> supperFieldMap = getFieldMap(obj, clz.getSuperclass().getDeclaredFields(),
                ignoreNull);

        fieldMap.putAll(supperFieldMap);

        return fieldMap;
    }

    private static Map<String, String> getFieldMap(Object obj, Field[] fields, boolean ignoreNull) {
        Map<String, String> params = new HashMap<>();
        //====1.取当前类字段
        for (Field field : fields) {
            try {
                field.setAccessible(Boolean.TRUE);
                Object value = field.get(obj);
                // 空值跳过
                if (value == null || field.isAnnotationPresent(JsonIgnore.class)) {
                    if (ignoreNull) {
                        continue;
                    } else {
                        value = "";
                    }
                }
                // 取字段别名
                String name = field.getName();
                if (field.isAnnotationPresent(JSONField.class)) {
                    JSONField jsonField = field.getAnnotation(JSONField.class);
                    String aliasName = jsonField.name();
                    if (StringUtils.isNotBlank(aliasName)) {
                        name = aliasName;
                    }
                }
                params.put(name, String.valueOf(value));
            } catch (IllegalAccessException e) {
                log.error(e.getMessage(), e);
            }
        }
        return params;
    }
}
